#include "http.h"
#include "FileUtils.h"
#include "ConfigReader.h"
#include "http-config.h"
#include <iostream>
#include <string.h>
/**
 * HttpRequest对象行为定义
 * 
 */
HttpRequest::HttpRequest(socketinf si) {
    this->si = si;
    fp = fdopen(si.socket_fd, "r");
    if (fp == NULL) {
        throw SocketException("fdopen error");
    }
    parseHeader();
    parseParameter(queryString);
}

HttpRequest::~HttpRequest() { 
    if (fp) fclose(fp);
}

std::string HttpRequest::getParameter(std::string &name) {
    if (parameters.count(name) == 0) {
        return std::string();
    } else {
        return parameters[name];
    }
}

void HttpRequest::parseParameter(std::string &input) {
    int pos,end,begin;
    pos = end = begin = 0;
    std::string key, value;
    while ( (pos = input.find('=', end)) != -1 ) {
        if ( (end = input.find('&', pos)) == -1 ) {
            end = input.length();
        }
        key = input.substr(begin, pos - begin);
        value = input.substr(pos + 1, end - pos - 1);
        begin = end + 1;
        parameters[key] = value;
    }
}

std::string HttpRequest::getQueryString() {
    return queryString;
}

void HttpRequest::parseHeader() {
    size_t len;
    char buf[8192] = {0};
    fgets(buf, 8192, fp);
    len = strlen(buf);
    if (len < 2) {
        throw Exception("HTTP Request Error");
    }
    // 解析起始行
    buf[----len] = 0;
    int pos[2], cnt = 0;
    for (size_t i = 0; i < len; i++) {
        if (buf[i] == ' ') {
            pos[cnt++] = i;
            buf[i] = 0;
        }
    }
    method = buf;
    url = buf + pos[0] + 1;
    // 解析Header
    int sub_pos;
    char * sub_str;
    while ( strcmp(fgets(buf, 8192, fp), "\r\n") )
    {
        len = strlen(buf);
        buf[----len] = 0;
        sub_str = strstr(buf, ":");
        sub_pos = sub_str - buf;
        if (sub_pos < 0) headers[buf] = "";
        else {
            buf[sub_pos++] = 0;
            sub_str++;
            if(sub_str[0] == ' ') sub_str++;
            headers[buf] = sub_str;
        }
    }
    int p = url.find('?');
    if (p == -1) {
        uri = url;
    } else {
        queryString = url.substr(p + 1);
        uri = url.substr(0, p);
    }
}

std::string HttpRequest::getHeader(const std::string &name) {
    if (headers.count(name) == 0) {
        return nullptr;
    } else {
        return headers[name];
    }
}

std::string HttpRequest::getURI() {
    return uri;
}

std::string HttpRequest::getMethod() {
    return method;
}


/***************************************************
 * HttpResponse对象行为定义
 * 
 ***************************************************/

void HttpResponse::sendFile(HttpRequest &request, std::string &localFile, std::string contenttype) {
    FileInfo fi;
    FILE *fp;
    char buf[8192];
    int cnt;
    try {
        fi.loadFromLocal(localFile);
        if(fi.isDir())                          throw FileException("is a directory");
        if ( !(fp = fopen(localFile.c_str(), "rb") ) )  throw Exception(strerror(errno));
        this->setContentLength(fi.size)
            .setContentType(contenttype);
        while ( !feof(fp) ) {
            cnt = fread(buf, 1, 8192, fp);
            this->write(buf, cnt);
        }
        fclose(fp);
    } catch(const FileException& e) {
        WebRouteMapper::getErrorController(404)
                        ->service(request, *this);
    } catch(...) {
        if(fp) fclose(fp);
    }
}

void HttpResponse::sendFile(HttpRequest &request, std::string &localFile) {
    sendFile(request, localFile, MimeType::get(FileInfo::getSuffix(localFile)));
}

HttpResponse::HttpResponse(socketinf si) {
    this->si = si;
    setHeader("Connection", "close");
}

HttpResponse& HttpResponse::setHeader(std::string name, std::string value){
    headers[name] = value;
    return *this;
}

HttpResponse& HttpResponse::setStatus(int code, const char * msg = "OK") {
    this->status = code;
    this->msg = msg;
    return *this;
}

HttpResponse& HttpResponse::setContentType(std::string v){
    return setHeader("Content-Type", v);
}

HttpResponse& HttpResponse::setContentLength(ssize_t s) {
    return setHeader("Content-Length", std::to_string(s));
}

std::string HttpResponse::getHeaderContext() {
    std::string context;
    context.append("HTTP/1.1 ").append(std::to_string(status)).append(" ").append(msg).append("\r\n");
    auto end = headers.end();
    for (auto i = headers.begin(); i != end; i++) {
        context.append(i->first).append(": ").append(i->second).append("\r\n");
    }
    context.append("\r\n");
    return context;
}

/**
 * 向客户端发送二进制数据
 * 出错抛出SocketException
 * @throw SocketException
 */
void HttpResponse::write(const char * data, ssize_t len) {
    if (!hasSendHeader) {
        std::string h = getHeaderContext();
        nettool::send(si.socket_fd, h.c_str(), h.length());
    }
    nettool::send(si.socket_fd, data, len);
}

/**
 * 向客户端发送字符串
 * 出错抛出SocketException
 * @throw SocketException
 */
void HttpResponse::write(std::string &data) {
    write(data.c_str(), data.length());
}

std::map<std::string, HttpController*> routeMap;
std::map<std::string, std::string> MimeType::typemap;

void MimeType::set(std::string suffix, std::string type) {
    typemap[suffix] = type;
}
std::string MimeType::get(const std::string &suffix) {
    if(typemap.count(suffix) == 0) {
        return "application/octet-stream";
    } else {
        return typemap[suffix];
    }
}
